const { ccclass, property } = cc._decorator;
import RefreshNodePool from './RefreshNodeControl';
import StatusNodePool from './StatusNodeControl';
import MyEnums from '../MyEnums';
import RefreshAim from './RefreshAim';
import AnimEndDestroy from './AnimEndDestroy';

class AttackItem {
    hitSource: number;
    attribute: number;
    type: number;
    value: number;
    duration: number;
    dynamic: boolean;
    recovery: boolean;
}

@ccclass
export default class TargetBase extends cc.Component {
    @property(cc.Node)
    RefresPool: cc.Node = null;
    @property(cc.Node)
    StatusPool: cc.Node = null;
    @property(cc.Node)
    statusNode: cc.Node = null;//状态动画节点
    @property(cc.Node)
    lifeValueNode: cc.Node = null;//掉血提示节点
    @property
    source: number = MyEnums.SkillSource.hero;

    //#region SkillRefreshType类型参数
    _RefreshTypeList: AttackItem[] = [];
    _RefreshList: cc.Node[] = [];
    //#endregion

    //#region SkillStatusType类型参数
    _StatusTypeList: AttackItem[] = [];
    _StatusList: cc.Node[] = [];
    //#endregion

    _AttributeList: boolean[] = [];
    _RefresPool: RefreshNodePool = null;
    _StatusPool: StatusNodePool = null;
    _showLife: number = 0;
    _isStartUpdate: boolean = false;
    _rollBackList: Map<number, number> = null;
    _isRollBack: boolean = false;//是否开启回滚

    onLoad() {
        this.init();
    }
    init() {
        this._RefreshList = [null, null, null, null, null, null, null, null, null, null, null, null, null];
        this._StatusList = [null, null, null, null, null, null, null];
        this._AttributeList = [false, false, false, false, false];
    }
    stopUpadate() {
        if (this._isStartUpdate) {
            this._isStartUpdate = false;
            this.unschedule(this.updateStatus);
        }
    }
    startUpdate() {
        if (!this._isStartUpdate) {
            this._isStartUpdate = true;
            this.schedule(this.updateStatus, 1);
        }
    }
    /**
     *  添加伤害
     * @param source 
     * @param attribute 
     * @param _AttackItem 
     */
    setStatusAttack(hitSource: number, attribute: number, _AttackItem: any[]) {
        let list: Map<number, number> = new Map<number, number>();
        let listRoll: Map<number, number> = new Map<number, number>();
        if (!this._StatusPool)
            this._StatusPool = this.StatusPool.getComponent(StatusNodePool);
        for (let ii = 0; ii < _AttackItem.length; ii++) {
            let _value = _AttackItem[ii].value * this._StatusPool.getCoffe(attribute, this._AttributeList);
            if (_value == 0)
                continue;
            let statusType = new AttackItem();
            statusType.value = _value;
            statusType.hitSource = hitSource;
            statusType.attribute = attribute;
            statusType.type = _AttackItem[ii].type;
            statusType.duration = _AttackItem[ii].duration;
            statusType.dynamic = _AttackItem[ii].dynamic;
            statusType.recovery = _AttackItem[ii].recovery;
            if (statusType.recovery) {
                this.addMapList(listRoll, _AttackItem[ii].type, _value);
            }
            else {
                this.addMapList(list, _AttackItem[ii].type, _value);
            }
            this._StatusTypeList.push(statusType);
            if (attribute)
                this._AttributeList[attribute] = true;
        }
        this._isRollBack = false;
        list.forEach((value, key) => {
            if (value != 0) {
                this.updateStatusAttack(key, value);
                this.setStatusNode(value, key);
            }
        })
        this._isRollBack = true;
        listRoll.forEach((value, key) => {
            if (value != 0) {
                this.updateStatusAttack(key, value);
                this.setStatusNode(value, key);
            }
        })
        if (!this._isStartUpdate) {
            this.startUpdate();
        }
    }
    /**
     * 添加伤害
     * @param source 
     * @param attribute 
     * @param _AttackItem 
     * @param _default 
     */
    setRefreshAttack(hitSource: number, attribute: number, _AttackItem: any[], _default?: any) {
        let list: Map<number, number> = new Map<number, number>();
        let listRoll: Map<number, number> = new Map<number, number>();
        if (!this._RefresPool)
            this._RefresPool = this.RefresPool.getComponent(RefreshNodePool);
        for (let ii = 0; ii < _AttackItem.length; ii++) {
            let _value = _AttackItem[ii].value * this._RefresPool.getCoffe(attribute, this._AttributeList);
            if (_value == 0)
                continue;
            if (_AttackItem[ii].duration > 0) {
                if (!this._isStartUpdate) {
                    this.startUpdate();
                }
                let statusType = new AttackItem();
                statusType.value = _value;
                statusType.hitSource = hitSource;
                statusType.attribute = attribute;
                statusType.type = _AttackItem[ii].type;
                statusType.duration = _AttackItem[ii].duration;
                statusType.dynamic = _AttackItem[ii].dynamic;
                statusType.recovery = _AttackItem[ii].recovery;
                if (!_AttackItem[ii].dynamic) {
                    if (statusType.recovery) {
                        this.addMapList(listRoll, _AttackItem[ii].type, _value);
                    }
                    else {
                        this.addMapList(list, _AttackItem[ii].type, _value);
                    }
                }
                this._RefreshTypeList.push(statusType);
                if (attribute)
                    this._AttributeList[attribute] = true;
            }
            else {
                this.addMapList(list, _AttackItem[ii].type, _value);
            }
        }
        if (_default) {
            this.addMapList(list, _default.type, _default.value);
        }
        this._isRollBack = false;
        list.forEach((value, key) => {
            if (value != 0) {
                this.updateRefreshAttack(key, value);
                this.setRefreshNode(value, key);
            }
        })
        this._isRollBack = true;
        listRoll.forEach((value, key) => {
            if (value != 0) {
                this.updateRefreshAttack(key, value);
                this.setRefreshNode(value, key);
            }
        })
    }
    private updateStatus() {
        let bl: boolean = false;
        if (this._RefreshTypeList.length > 0) {
            bl = true;
            let list: Map<number, number> = new Map<number, number>();
            let listRoll: Map<number, number> = new Map<number, number>();
            let deletes: AttackItem[] = [];
            for (let i = 0; i < this._RefreshTypeList.length; i++) {
                let value = this._RefreshTypeList[i].value;
                let type = this._RefreshTypeList[i].type;
                if (this._RefreshTypeList[i].dynamic) {
                    if (this._RefreshTypeList[i].duration > 1) {
                        this._RefreshTypeList[i].duration -= 1;
                    }
                    else {
                        value *= this._RefreshTypeList[i].duration;
                        this._RefreshTypeList[i].duration = 0;
                        deletes.push(this._RefreshTypeList[i]);
                    }
                    if (this._RefreshTypeList[i].recovery) {
                        this.addMapList(listRoll, type, value);
                    }
                    else {
                        this.addMapList(list, type, value);
                    }
                }
                else {
                    if (this._RefreshTypeList[i].duration > 1) {
                        this._RefreshTypeList[i].duration -= 1;
                    }
                    else {
                        this._RefreshTypeList[i].duration = 0;
                        deletes.push(this._RefreshTypeList[i]);
                    }
                }
            }
            this._isRollBack = false;
            list.forEach((value, key) => {
                this.updateRefreshAttack(key, value);
                this.setRefreshNode(value, key);
            })
            this._isRollBack = true;
            listRoll.forEach((value, key) => {
                this.updateRefreshAttack(key, value);
                this.setRefreshNode(value, key);
            })
            deletes.forEach(element => {
                let ii = this._RefreshTypeList.indexOf(element);
                this._RefreshTypeList.splice(ii, 1);
                this.deleteRefreshType(element);
            });
        }
        if (this._StatusTypeList.length > 0) {
            bl = true;
            let deletes: AttackItem[] = [];
            let StatusList: boolean[] = [false, false, false, false, false, false, false];
            for (let i = 0; i < this._StatusTypeList.length; i++) {
                if (this._StatusTypeList[i].duration > 1) {
                    this._StatusTypeList[i].duration -= 1;
                    StatusList[this._StatusTypeList[i].type] = true;
                }
                else {
                    this._StatusTypeList[i].duration = 0;
                    deletes.push(this._StatusTypeList[i]);
                }
            }
            deletes.forEach(element => {
                let ii = this._StatusTypeList.indexOf(element);
                this._StatusTypeList.splice(ii, 1);
                this.deleteStatusType(element, StatusList[element.type]);
            });
        }
        this.showLife(this._showLife);
        if (!bl) {
            this.stopUpadate();
        }
    }
    private deleteStatusType(_AttackItem: AttackItem, retainAnim: boolean) {
        let type = _AttackItem.type;
        //删除状态动画
        if (!retainAnim) {
            let node = this._StatusList[type];
            if (node) {
                let control = node.getComponent(RefreshAim);
                control.onLastFrame();
                this._StatusList[type] = null;
            }
        }

        //是否回滚
        if (_AttackItem.recovery) {
            let reValue = _AttackItem.value;
            if (_AttackItem.dynamic) {
                reValue = _AttackItem.value * _AttackItem.duration;
            }
            this.rollBackStatus(type, reValue);
        }

        //更新属性
        if (_AttackItem.attribute) {
            this._AttributeList[_AttackItem.attribute] = false;
            this._StatusTypeList.forEach(element => {
                if (element && element.attribute == _AttackItem.attribute)
                    this._AttributeList[_AttackItem.attribute] = true;
            });
        }
    }
    private deleteRefreshType(_AttackItem: AttackItem) {
        let type = _AttackItem.type;
        // //删除状态动画
        // let node = this._RefreshList[type];
        // if (node) {
        //     let control = node.getComponent(RefreshAim);
        //     control.onLastFrame();
        //     this._RefreshList[type] = null;
        // }

        //是否回滚
        if (_AttackItem.recovery) {
            let reValue = _AttackItem.value;
            if (_AttackItem.dynamic) {
                reValue = _AttackItem.value * _AttackItem.duration;
            }
            this.rollBackRefresh(type, reValue);
        }

        //更新属性
        if (_AttackItem.attribute) {
            this._AttributeList[_AttackItem.attribute] = false;
            this._RefreshTypeList.forEach(element => {
                if (element && element.attribute == _AttackItem.attribute)
                    this._AttributeList[_AttackItem.attribute] = true;
            });
        }
    }
    //#region 设置状态动画
    setStatusNode(value: number, type: number) {
        if (this._StatusList[type]) {
            return;
        }
        if (this.source == MyEnums.SkillSource.monster && type == MyEnums.SkillStatusType.Common) {
            return;
        }
        if (this.source == MyEnums.SkillSource.hero && type == MyEnums.SkillStatusType.purifica) {
            return;
        }
        let _statusNode = null;
        if (!this._StatusPool)
            this._StatusPool = this.StatusPool.getComponent(StatusNodePool);
        if (type == MyEnums.SkillRefreshType.attack) {
            if (value > 0) {
                _statusNode = this._StatusPool.getNodePool(type);
            }
        }
        else {
            if (value < 0) {
                _statusNode = this._StatusPool.getNodePool(type);
            }
        }
        if (_statusNode) {
            this.setStatus(_statusNode, type, false);
            this._StatusList[type] = _statusNode;
        }
    }
    setRefreshNode(value: number, type: number) {
        if (this._RefreshList[type]) {
            return;
        }
        if (this.source == MyEnums.SkillSource.monster && type == MyEnums.SkillRefreshType.life) {
            return;
        }
        let _statusNode = null;
        if (!this._RefresPool)
            this._RefresPool = this.RefresPool.getComponent(RefreshNodePool);
        if (type == MyEnums.SkillRefreshType.attack) {
            if (value > 0) {
                _statusNode = this._RefresPool.getNodePool(type);
            }
            else {
                _statusNode = this._RefresPool.getNodePool_(type);
            }
        }
        else {
            if (value < 0) {
                _statusNode = this._RefresPool.getNodePool(type);
            }
            else {
                _statusNode = this._RefresPool.getNodePool_(type);
            }
        }
        if (_statusNode) {
            this.setStatus(_statusNode, type, true);
            this._RefreshList[type] = _statusNode;
        }
    }
    setStatus(_statusNode: cc.Node, type: number, isRefresh: boolean) {
        let control: RefreshAim = null;
        control = _statusNode.getComponent(RefreshAim);
        if (!control) {
            control = _statusNode.addComponent(RefreshAim);
        }
        control._TargetBase = this;
        control._isRefresh = isRefresh;
        control._type = type;
        control.init();
        this.statusNode.addChild(_statusNode);
    }
    deleteRefreshNode(type: number, isRefresh: boolean, _isAttack: boolean, _node: cc.Node) {
        if (type == -1)//血量标签显示
        {
            this._RefresPool.setSkillValuePool(_node);
        }
        else {
            if (isRefresh) {
                this._RefreshList[type] = null;
                if (_isAttack)
                    this._RefresPool.setNodePool(type, _node);
                else
                    this._RefresPool.setNodePool_(type, _node);
            }
            else {
                this._StatusList[type] = null;
                this._StatusPool.setNodePool(type, _node);
            }
        }
    }
    //#endregion
    //显示掉血数值
    showLife(Life: number) {
        if (!this._RefresPool)
            this._RefresPool = this.RefresPool.getComponent(RefreshNodePool);
        let _statusNode = this._RefresPool.getSkillValuePool();
        let _label = _statusNode.getComponent(cc.Label);
        if (Life > 0) {
            _statusNode.color = cc.color(0, 255, 0);
            _label.string = "+" + Life.toString();
        }
        else if (Life < 0) {
            _statusNode.color = cc.color(255, 0, 0);
            _label.string = Life.toString();
        }
        else {
            _statusNode.color = cc.color(0, 255, 0);
            _label.string = "免疫";
        }
        this._showLife = 0;
        let control: AnimEndDestroy = null;
        control = _statusNode.getComponent(AnimEndDestroy);
        if (!control) {
            control = _statusNode.addComponent(AnimEndDestroy);
        }
        control._TargetBase = this;
        control.init();
        if (this.lifeValueNode.children?.length > 0)
            _statusNode.x = -30;
        else if (this.lifeValueNode.children?.length > 1)
            _statusNode.x = 30;
        this.lifeValueNode.addChild(_statusNode);
    }
    private updateRefreshAttack(type: number, value: number, isRollBack: boolean = false) {
        switch (type) {
            case MyEnums.SkillRefreshType.armorA:
                {
                    this.armorA(value);
                    break;
                }
            case MyEnums.SkillRefreshType.armorC:
                {
                    this.armorC(value);
                    break;
                }
            case MyEnums.SkillRefreshType.attack:
                {
                    this.attack(value, isRollBack);
                    break;
                }
            case MyEnums.SkillRefreshType.cdWaySpeed:
                {
                    this.cdWaySpeed(value);
                    break;
                }
            case MyEnums.SkillRefreshType.cdDamage:
                {
                    this.cdDamage(value);
                    break;
                }
            case MyEnums.SkillRefreshType.cdHeroSpeed:
                {
                    this.cdHeroSpeed(value);
                    break;
                }
            case MyEnums.SkillRefreshType.cdJump:
                {
                    this.cdJump(value);
                    break;
                }
            case MyEnums.SkillRefreshType.damageSpeed:
                {
                    this.damageSpeed(value, isRollBack);
                    break;
                }
            case MyEnums.SkillRefreshType.jumpSpeed:
                {
                    this.jumpSpeed(value, isRollBack);
                    break;
                }
            case MyEnums.SkillRefreshType.life:
                {
                    this.life(value, type);
                    break;
                }
            case MyEnums.SkillRefreshType.maxLife:
                {
                    this.maxLife(value, isRollBack);
                    break;
                }
            case MyEnums.SkillRefreshType.resLife:
                {
                    this.resLife(value);
                    break;
                }
            case MyEnums.SkillRefreshType.runSpeed:
                {
                    this.runSpeed(value, isRollBack);
                    break;
                }
        }
    }
    private updateStatusAttack(type: number, value: number, isRollBack: boolean = false) {
        switch (type) {
            case MyEnums.SkillStatusType.Common:
                {
                    this.StatusCommon(value, type);
                    break;
                }
            case MyEnums.SkillStatusType.dizziness://眩晕
                {
                    this.StatusDizziness(value);
                    break;
                }
            case MyEnums.SkillStatusType.fire://灼烧
                {
                    this.StatusFire(value, isRollBack);
                    break;
                }
            case MyEnums.SkillStatusType.freeze://冰冻
                {
                    this.StatusFreeze(value);
                    break;
                }
            case MyEnums.SkillStatusType.poison://中毒
                {
                    this.StatusPoison(value, isRollBack);
                    break;
                }
            case MyEnums.SkillStatusType.purifica://净化
                {
                    this.StatusPurifica(value);
                    break;
                }
            case MyEnums.SkillStatusType.slowness://虚弱
                {
                    this.StatusSlowness(value, isRollBack);
                    break;
                }
        }
    }
    rollBackStatus(type: number, value: number) {
        this.updateStatusAttack(type, 0 - value, true);
    }
    rollBackRefresh(type: number, value: number) {
        value = this.checkRollBack(type, 0 - value);
        this.updateRefreshAttack(type, value, true);
    }
    checkRollBack(type: number, value: number): number {
        if (this._rollBackList?.has(type)) {
            let _value = this._rollBackList.get(type);
            if (_value * value > 0) {
                if (Math.abs(value) >= Math.abs(_value)) {
                    value -= _value;
                    this._rollBackList.delete(type);
                }
            }
        }
        return value;
    }
    setRollBackStatus(type: number, _value: number) {
        if (this._rollBackList == null)
            this._rollBackList = new Map<number, number>();
        if (!this._rollBackList.has(type))
            this._rollBackList.set(type, _value);
    }
    clearSkills() {
        this._RefreshList.forEach(element => {
            if (element) {
                element.destroy();
            }
        });
        this._StatusList.forEach(element => {
            if (element) {
                element.destroy();
            }
        });
        this._RefreshTypeList = [];
        this._StatusTypeList = [];
        this._rollBackList = null;
        this.init();
        this.stopUpadate();
    }
    addMapList(list: Map<number, number>, type: number, _value: number) {
        if (list.has(type)) {
            let V = list.get(type);
            list.set(type, V + _value);
        }
        else
            list.set(type, _value);
    }
    //#region 需要子类重写
    protected resLife(value: number) {

    }
    protected life(value: number, type: number) {

    }
    protected armorC(value: number) {

    }
    protected armorA(value: number) {

    }
    protected cdJump(value: number) {

    }
    protected cdHeroSpeed(value: number) {

    }
    protected cdDamage(value: number) {

    }
    protected cdWaySpeed(value: number) {

    }
    protected StatusCommon(value: number, type: number) {

    }
    protected StatusFreeze(value: number) {

    }
    protected StatusDizziness(value: number) {

    }
    protected StatusPurifica(value: number) {

    }

    protected runSpeed(value: number, isRollBack: boolean = false) {

    }
    protected maxLife(value: number, isRollBack: boolean = false) {

    }
    protected jumpSpeed(value: number, isRollBack: boolean = false) {

    }
    protected damageSpeed(value: number, isRollBack: boolean = false) {

    }
    protected attack(value: number, isRollBack: boolean = false) {

    }
    protected StatusPoison(value: number, isRollBack: boolean = false) {

    }
    protected StatusFire(value: number, isRollBack: boolean = false) {

    }
    protected StatusSlowness(value: number, isRollBack: boolean = false) {

    }

    public playSound() {

    }
    //#endregion
}
